﻿/* 
 * THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE 
 * ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE 
 * OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
 * 
 * BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE 
 * TERMS OF THIS LICENSE. THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF 
 * YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
 * 
 * http://creativecommons.org/licenses/by-sa/2.5/legalcode
 */

// Originally from Dan Tao's excellent answer here:
// http://stackoverflow.com/questions/2417647/is-there-an-equivalent-to-javas-tostringbuilder-for-c-what-would-a-good-c-ver/2417736#2417736

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;

namespace CatchUpTv.Utilities
{
    public sealed class ToStringBuilder<T>
    {
        private T _obj;
        private Type _objType;
        private StringBuilder _innerSb;

        public ToStringBuilder(T obj)
        {
            _obj = obj;
            _objType = obj.GetType();
            _innerSb = new StringBuilder();
        }

        public ToStringBuilder<T> Append<TProperty>(Expression<Func<T, TProperty>> expression)
        {
            string propertyName;

            if (!TryGetPropertyName(expression, out propertyName))
            {
                throw new ArgumentException("Expression must be a simple property expression.");
            }

            Func<T, TProperty> func = expression.Compile();

            if (_innerSb.Length < 1)
            {
                _innerSb.Append(propertyName + ": " + func(_obj).ToString());
            }
            else
            {
                Object o = func(_obj);
                String value = o == null ? "null" : o.ToString();
                _innerSb.Append(", " + propertyName + ": " + value);
            }

            return this;
        }

        private static bool TryGetPropertyName<TProperty>(Expression<Func<T, TProperty>> expression, out string propertyName)
        {
            propertyName = default(string);

            var propertyExpression = expression.Body as MemberExpression;

            if (propertyExpression == null)
            {
                return false;
            }

            propertyName = propertyExpression.Member.Name;

            return true;
        }

        public override string ToString()
        {
            return _objType.Name + "{" + _innerSb.ToString() + "}";
        }
    }
}
